#include "ProcManager.h"
#include <process.h>
#include "Wmi.h"


// Constructor
ProcManager::ProcManager(NodeManager *nm, TaskManager *tm, Log *log) {
	this->nm = nm;
	this->tm = tm;
	this->curr = NULL;

	this->log = log;
	this->cpu = new Cpu(log);
}

// Is there cpu ready to start a new thread
// returns true if cpu is less than 80%
bool ProcManager::isReadyCPU() {
	// pretend to be watching the cpu, returns true if < 2 threads are active
	Task *slider = this->tm->head;

	while(slider) {
		if(slider->state == ACTIVE) {
			if(cpu->getPercent() < 50) {
				return true;
			}
			else {
				return false;
			}
/*			if(slider->bm.getActive() == this->cpu->params.threads_allowed) {
				return false;
			}
*/		}

		slider = slider->next;
	}

	return false;
}

// Is there a task ready to be worked on?
char* ProcManager::isReadyTask() {
	Task *slider = this->tm->head;

	while(slider) {
		if(slider->state == ACTIVE) {
			return slider->id;
		}

		slider = slider->next;
	}

	return false;
}

// get the next task ready to have its thread count increased
char* ProcManager::getAddThread(int max_threads) {
	// get back to the same curr index we were at last call
	Task *slider = tm->reset();
	if(slider == NULL) {
		return NULL;	// exit if no tasks
	}
	if(curr == NULL) {
		curr = slider;
	}
	else if(slider == curr) {
		// prev task located, advance to next task
		curr = this->tm->getNext();
	}
	else {
		// we need to advance to the prev task
		while(slider) {
			slider = tm->getNext();
			if(slider) {
				if(slider == curr) {
					// prev task located, advance to next task
					curr = tm->getNext();
					break;
				}
			}
		}
		// previous curr does not exit, use starting task instead
		if(slider == NULL) {
			curr = tm->reset();		// This breaks impartial selection... could be improved
		}
	}

	while(curr) {
		if(curr->isDrone) {
		if(atoi(curr->pm.get("priority")) == this->pri.getCurr()) {
			if(curr->state == ACTIVE) {
				if(curr->threads < max_threads) {
					// locate node to process type of task
					Node *node = nm->get(curr->pm.get("todo"));
					if(node == NULL) {
						printf("Failed to locate node, ignoring task.\r\n");
						printf("[todo] Should modify code to only ask for blocks w/ supported tasks.\r\n");
					}
					else {
						return curr->id;
					}
				}
			}
		}
		}
		
		// get the next task to check
		curr = this->tm->getNext();
		if(!curr) {
			// if at end of task list, reset to begining
			curr = this->tm->reset();

			// if at end of task list, advance to next priority
			if(this->pri.getNext() == -1) {
				// break out of loop when end of priority is reached, this
				// avoids a possible infinite loop if tasks exist but there
				// are no blocks to work on
				break;
			}
		}
	}

	return NULL;
}

// get the next task ready to have its thread count decreased
char* ProcManager::getDelThread(int min_threads) {
	// get back to the same curr index we were at last call
	Task *slider = tm->reset();
	if(slider == NULL) {
		return NULL;	// exit if no tasks
	}
	if(curr == NULL) {
		curr = slider;
	}
	else if(slider == curr) {
		// prev task located, advance to next task we want
		curr = this->tm->getPrev();
	}
	else {
		// we need to advance to the prev task
		while(slider) {
			slider = tm->getNext();
			if(slider) {
				if(slider == curr) {
					// prev task located, advance to next task we want
					curr = tm->getPrev();
					break;
				}
			}
		}
		// previous curr does not exit, use starting task instead
		if(slider == NULL) {
			curr = tm->reset();		// This breaks impartial selection... could be improved
		}
	}

	while(curr) {
		if(curr->isDrone) {
		if(atoi(curr->pm.get("priority")) == this->pri.getCurr()) {
			if(curr->state == ACTIVE) {
				if(curr->threads > min_threads) {
					// locate node to process type of task
					Node *node = nm->get(curr->pm.get("todo"));
					if(node == NULL) {
						printf("Failed to locate node, ignoring task.\r\n");
						printf("[todo] Should modify code to only ask for blocks w/ supported tasks.\r\n");
					}
					else {
						return curr->id;
					}
				}
			}
		}
		}
		
		// get the next task to check
		curr = this->tm->getPrev();
		if(!curr) {
			// if at end of task list, reset to begining
			curr = this->tm->reset();
			// forward to last node, because 'del' goes in reverse
			if(curr) {
				while(curr->next != NULL) {
					curr = this->tm->getNext();
				}
			}

			// if at end of task list, advance to next priority
			if(this->pri.getPrev() == -1) {
				// break out of loop when end of priority is reached, this
				// avoids a possible infinite loop if tasks exist but there
				// are no blocks to work on
				break;
			}
		}
	}

	return NULL;
}

// for debug, dumps each task's block status
void ProcManager::dump() {
/*	Task *slider = this->tm->head;
	char data[DEFAULT_BUFLEN];

	while(slider) {
		if(slider->state == ACTIVE) {
//			slider->bm.update();

			if(slider->bm.head) {
				sprintf(data, "STATUS task_id = %s, index = %s, [%d, %d, %d]\r\n",
					slider->id, slider->bm.head->index,
					slider->bm.getPending(),
					slider->bm.getActive(),
					slider->bm.getComplete()
					);
			}
			else {
				sprintf(data, "STATUS task_id = %s, [%d, %d, %d]\r\n",
					slider->id,
					slider->bm.getPending(),
					slider->bm.getActive(),
					slider->bm.getComplete()
					);	
			}

			log->write(data);
		}

		slider = slider->next;
	}
*/
}
